import base64
import json
import pickle

from django import http
from django.http import HttpResponseBadRequest, JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU

from utils import constants
from utils.response_code import RETCODE


class CartsView(View):

    def get(self, request):
        user = request.user

        if user.is_authenticated:
            # 已登录
            # 从redis获取数据返回
            redis_con = get_redis_connection("shoppingcart")
            user_sku = redis_con.hgetall("shopping_cart_%s" % user.id)
            selected = redis_con.smembers("selected_%s" % user.id)

            cart_dict = {}
            for k, v in user_sku.items():
                cart_dict[int(k)] = {
                    "count": v,
                    "selected": k in selected
                }

        else:
            # 1、从cookie里获取数据
            cart = request.COOKIES.get("cart")
            try:
                cart_dict = pickle.loads(base64.b64decode(cart))
            except Exception as e:
                cart_dict = {}
        if cart_dict is None:
            return render(request, "cart.html")

        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': int(cart_dict.get(sku.id).get('count')),
                'selected': str(cart_dict.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url': sku.default_image,
                'price': str(sku.price),  # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount': str(sku.price * int(cart_dict.get(sku.id).get('count'))),
            })
        print("cart_skus", cart_skus)
        context = {
            'cart_skus': cart_skus
        }

        return render(request, "cart.html", context)

    def post(self, request):
        # 1、获取数据
        json_data = json.loads(request.body.decode())
        sku_id = json_data.get("sku_id")
        count = json_data.get("count")
        selected = json_data.get("selected", True)

        # 2、校验数据
        # 2.1 判断一下传入的sku_id是否存在
        try:
            SKU.objects.get(id=sku_id)
        except Exception as e:
            return render(request, "404.html")
        # 2.2 判断一下count是否为整数
        try:
            int(count)
        except Exception as e:
            return HttpResponseBadRequest("传入的参数有误")
        # 3.3 校验selected是否为布尔值
        if not isinstance(selected, bool):
            return HttpResponseBadRequest("传入的参数有误")

        # 判断一下用户是否是登录状态
        user = request.user
        if user.is_authenticated:
            """已登录---->>>数据存储到redis里"""
            # 连接redis
            redis_con = get_redis_connection("shoppingcart")
            pipeline = redis_con.pipeline()
            pipeline.hincrby("shopping_cart_%s" % user.id, sku_id, count)
            if selected:
                pipeline.sadd("selected_%s" % user.id, sku_id)
            pipeline.execute()
            return JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})

        else:
            """未登录---->>>数据存储到session"""
            # 获取存储到本地的cookie值
            # 先从cookie里获取之前存储的商品，如果能获取的找，则在之前整合的字典里追加、如果获取不到、则使用新的字典
            cart = request.COOKIES.get("cart")
            if cart:
                cookie = pickle.loads(base64.b64decode(cart))
                cookie_dict = cookie
            else:
                cookie_dict = {}

            if sku_id not in cookie_dict:
                cookie_dict[sku_id] = {
                    "count": count,
                    "selected": selected,
                }
            else:
                # 如果添加的商品已存在，则数量加一
                cookie_dict[sku_id]["count"] += count

            cooke_data = base64.b64encode(pickle.dumps(cookie_dict)).decode()

            response = JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
            response.set_cookie("cart", cooke_data)
            return response

    def put(self, request):
        user = request.user
        # 获取数据
        json_dict = json.loads(request.body)
        count = json_dict.get("count")
        selected = json_dict.get("selected")
        sku_id = json_dict.get("sku_id")

        print('selected', selected)

        # 校验参数
        if not all([count, sku_id]):
            return HttpResponseBadRequest("缺少必传参数")

        try:
            sku_id = int(sku_id)
            count = int(count)
        except Exception as e:
            return HttpResponseBadRequest("传入的参数有误")

        # 判断selected是否为bool值
        if not isinstance(selected, bool):
            return HttpResponseBadRequest("传入的参数有误")

        # 判断sku_id是否存在
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseBadRequest('商品sku_id不存在')

        if user.is_authenticated:
            # 已登录
            # 1、校验传入的id是否存在
            redis_con = get_redis_connection("shoppingcart")
            redis_sku = redis_con.hget("shopping_cart_%s" % user.id, sku_id)

            if sku:
                # 2、修改数据
                try:
                    pl = redis_con.pipeline()
                    pl.hset("shopping_cart_%s" % user.id, sku_id, count)
                    if selected:
                        pl.sadd("selected_%s" % user.id, sku_id)
                    else:
                        pl.srem("selected_%s" % user.id, sku_id)
                    pl.execute()
                except Exception as e:
                    return HttpResponseBadRequest("数据修改失败")
            else:
                return HttpResponseBadRequest("该商品未添加到购物车")

            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image,
                'price': sku.price,
                'amount': sku.price * count,
            }
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改购物车成功', 'cart_sku': cart_sku})

        else:
            # 未登录
            cart_cookies = request.COOKIES.get('cart')

            # 判断cart_cookies是否存在
            if cart_cookies:
                carts = pickle.loads(base64.b64decode(cart_cookies))
                print("carts", carts)
            else:
                carts = {}

            if not carts.get(sku_id, False):
                return http.HttpResponseBadRequest('该商品未添加到购物车')

            carts[sku_id] = {
                'count': count,
                'selected': selected
            }
            print(carts)
            cookie_cart_str = base64.b64encode(pickle.dumps(carts)).decode()

            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image,
                'price': sku.price,
                'amount': sku.price * count,
            }
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改购物车成功', 'cart_sku': cart_sku})
            # 响应结果并将购物车数据写入到cookie
            response.set_cookie('cart', cookie_cart_str, max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        # 1、获取数据
        json_data = json.loads(request.body)
        sku_id = json_data.get("sku_id")

        # 2、校验数据
        # 2.1 是否有传入sku_id
        if not sku_id:
            return http.HttpResponseBadRequest("缺少必传参数！！！")

        # 校验用户是否登录
        user = request.user
        if user is not None and user.is_authenticated:
            # 已登录
            # 链接redis 校验传入的sku_id是否已经添加到购物车里
            redis_con = get_redis_connection("shoppingcart")
            pl = redis_con.pipeline()
            pl.hdel('shopping_cart_%s' % user.id, sku_id)
            pl.srem('selected_%s' % user.id, sku_id)
            pl.execute()

            # 删除结束后，没有响应的数据，只需要响应状态码即可
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
        else:
            # 未登录
            cookies = request.COOKIES
            if cookies:
                cart = pickle.loads(base64.b64decode(cookies.get("cart").encode()))
            else:
                cart = {}

            # 删除商品
            if sku_id in cart:
                cart.pop(sku_id)

            cookie = base64.b64encode(pickle.dumps(cart)).decode()
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
            response.set_cookie("cart", cookie, max_age=constants.CARTS_COOKIE_EXPIRES)

            return response


class SelectionView(View):
    def put(self, request):
        # 1、接收数据
        json_data = json.loads(request.body)
        selected = json_data.get("selected", True)

        # 2、校验传入的值是否为布尔值
        if not isinstance(selected, bool):
            return http.HttpResponseBadRequest("传入的参数有误！！！")

        # 3、判断用户是否为登录状态
        user = request.user
        if user is not None and user.is_authenticated:
            # 已登录
            # 链接reids数据库
            redis_con = get_redis_connection("shoppingcart")

            # 从数据库里取出所有商品
            data_all = redis_con.hgetall("shopping_cart_%s" % user.id)
            dict_key_list = data_all.keys()

            # 将商品id添加到selected
            if selected:
                redis_con.sadd("selected_%s" % user.id, *dict_key_list)
            else:
                redis_con.srem("selected_%s" % user.id, *dict_key_list)
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
        else:
            # 未登录
            cookies = request.COOKIES
            carts = pickle.loads(base64.b64decode(cookies.get("cart").encode()))
            if not carts:
                carts = {}

            if selected:
                for cart in carts.keys():
                    carts[cart]["selected"] = True
            else:
                for cart in carts.keys():
                    carts[cart]["selected"] = False

            response_cookie = base64.b64encode(pickle.dumps(carts)).decode()
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
            response.set_cookie('cart', response_cookie, max_age=constants.CARTS_COOKIE_EXPIRES)

        return response


class SimpleView(View):
    def get(self, request):
        # 1、校验一下当前用户是否登录
        user = request.user
        if user.is_authenticated:
            # 已登录  链接redis 将redis的购物车数据全部查询出来
            redis_con = get_redis_connection("shoppingcart")
            all_sku = redis_con.hgetall('shopping_cart_%s' % user.id)
            all_selected = redis_con.smembers('selected_%s' % user.id)
            # 将获取到的数据整成字典
            new_sku_dict = {}
            for k, v in all_sku.items():
                new_sku_dict[int(k)] = {
                    'count': int(v),
                    'selected': k in all_selected
                }

        else:
            # 未登录
            cart = request.COOKIES.get("cart")
            # 解码
            if cart:
                new_sku_dict = pickle.loads(base64.b64decode(cart.encode()))
            else:
                new_sku_dict = {}

        response_list = []
        print(new_sku_dict)
        dict_keys = new_sku_dict.keys()
        skus = SKU.objects.filter(id__in=dict_keys)
        for sku in skus:
            print(sku.id)
            response_list.append(
                {
                    "id": sku.id,
                    "name": sku.name,
                    "count": new_sku_dict[sku.id]["count"],
                    "default_image_url": sku.default_image
                })

        print("response_list", response_list)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'cart_skus': response_list})
